﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Transactions;

// Espacios SDK CRM 2011
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Messages;
using Microsoft.Xrm.Sdk.Query;

using System.ServiceModel;

// Web Services expuestos por HC
using HC.Int.Front2GoCityAccess.WsCityAccess;
using HC.Int.Front2GoCityAccess.WsFront2Go;
using HC.Int.Front2GoCityAccess.WsPropietario;

/// <summary>
/// Autor: Julio Esquivel 
/// Fecha Junio 2014
/// Descripción: Integración con F2G y City Access. APUNTE A PRUEBAS 
/// Entidad: Empresa (account)
/// Métodos: Create, Update. 
/// Contratos: Insert_compy, Update_compy
/// Liberación: 30 de Julio del 2014
/// Actualización: 11 de Agosto 2014
/// Descripción: Se coloca de manera rígida el tipo de contacto (5), ya que éste marcaba un error, al momento de hacer la relacion de contacto principal en F2G (setPersonToCompany).
///              Se agrega código para leer del catalogo de errores, el detalle -1 de City Access, cuando la empresa se encuentra duplicada.
///              Se coloca de manera rígida en los metodos de eliminacion a "rrivero" (administrador). Solucionar problema sobre si el usuario cuenta o no con privilegios.
/// Actualización: 12 Agosto 2014
/// Descripción: Corrige problema de no borrado de empresa en F2G, cuando el contacto marca error: "correo no válido", "correo ya existe" en F2G.
///              Se simplfican metodos de borrado. 
/// Actualización: 15 Agosto 2015. Se solicitó apuntar a pruebas.
/// Actualización: 27 Agosto 2014. Se solicita enviar siempre la IATA.
/// Actualización: 19 Septiembre 2014. Se considera la empresa asociada. Similar a Enviar empresa inplant.
/// Actualizacíón: 29 Octubre 2014. El WS de City Access devuelve ID y cambió el SetPersonToCompany. Sólo City Access.
/// </summary>

namespace HC.Int.Front2GoCityAccess
{
    public class IntegraEmpresa :IPlugin
    {  
        public void Execute(IServiceProvider ProveedorServicio)
        {           
            #region Consumo de Servicio de Organización y Variables de Contexto del plugin                
            // Limpiamos objetos de entidad y WS
            Entity Entidad = null;
            IOrganizationService Servicio = null;

            //Obtenemos el Contexto de ejecución del Plugin
            IPluginExecutionContext Contexto = (IPluginExecutionContext)ProveedorServicio.GetService(typeof(IPluginExecutionContext));

            // Validamos que exista un objeto de tipo Entity
            Entidad = ValidaContexto(Contexto, ProveedorServicio);

            try
            {
                // Consumimos el Servicio de Organización      
                Servicio = OrganizationServiceCrm.ObtenerServicioCallingUser(Contexto, ProveedorServicio);
                // Pasamos Objeto de Servicio a los métodos FesXrm
                MetodosFes InicializaServicio = new MetodosFes(Servicio);
            }
            catch (FaultException<OrganizationServiceFault> ex)
            {              
                throw new InvalidPluginExecutionException("Hoteles City ERROR CRM Consumo de Servicios de Organización. " + ex.Message);
            }
            #endregion

            #region Configuracion de WS
            // Configuramos Binding de Servicios
            BasicHttpBinding Front2Go_bin = new BasicHttpBinding();                
            BasicHttpBinding AsignaProp_bin = new BasicHttpBinding();

            Front2Go_bin.Name = "ws_PerfilesSoap";                
            AsignaProp_bin.Name = "ws_ConveniosSoap";

            EndpointAddress EndPointFront2Go = new EndpointAddress("http://200.79.228.19/whsEngine/ws_Perfiles.asmx");
            EndpointAddress EndPointAsignProp = new EndpointAddress("http://200.79.228.19/whsEngine/ws_Convenios.asmx");            

            // Instanciamos el objeto de los servicios                                    
            ws_PerfilesSoapClient Cliente_F2G = new ws_PerfilesSoapClient(Front2Go_bin, EndPointFront2Go);                
            ws_ConveniosSoapClient Cliente_Conve = new ws_ConveniosSoapClient(AsignaProp_bin, EndPointAsignProp);
            #endregion

            #region Proceso Principal que invoca la Integración de Empresa
            // Validamos que la entidad realmente sea Empresa
            if (Contexto.PrimaryEntityName.Equals("account"))
            {
                // Objeto entidad con que cotendrá la información de la Empresa
                Entity Emp = null;

                #region Columnas a recuperar de la empresa
                // Definimos Columnas a recuperar de información 
                ColumnSet Cols = new ColumnSet("new_rfc", "name", "address1_line1", "new_nmeroexterior", "new_interior", "new_tipodircompy", "new_contactoactualizado", "new_iata",
                                                "new_coloniaid", "new_delegacionmunicipioid", "new_tipocompy", "new_ciudadid", "primarycontactid", "statuscode", "accountid", "new_matrizactualizada",
                                                "new_estadoid", "address1_postalcode", "new_paisid", "new_telefono", "accountnumber", "ownerid", "new_codigocxc", "new_empresainplant", "parentaccountid", "new_resp_ca_ins_cmp");
                #endregion

                // Recuperamos los datos de la Empresa por el Guid
                Emp = Servicio.Retrieve("account", Contexto.PrimaryEntityId, Cols);

                // Se manda llamar método que realiza la Integración
                InsUpdEmpresa(Emp, Contexto.MessageName, Servicio, Contexto.PrimaryEntityId, Cliente_F2G, Cliente_Conve);
            }
            #endregion
        }

        #region # Método de validación del Contexto que recibe el Plugin
        private Entity ValidaContexto(IPluginExecutionContext Context, IServiceProvider Prov_Servicio)
        {
            Entity Ent = null; 

            if (Context.InputParameters.Contains("Target") && Context.InputParameters["Target"] is Entity)
                Ent = (Entity)Context.InputParameters["Target"];

            return Ent;
        }
        #endregion

        #region Método para el envío de información por Integración
        private void InsUpdEmpresa(Entity Empresa, string Mensaje, IOrganizationService Serv, Guid EmpresaId, ws_PerfilesSoapClient Cliente_Front2Go, ws_ConveniosSoapClient Cliente_Prop)
        {
            #region Declaración de Variables locales
            int Resp_Front_ins_cmp = 0;
            //Resultado Resp_CityAcc_ins_cmp = null;
            int Resp_CityAcc_ins_cmp = 100;
            int Resp_Front_upd_cmp = 100;
            int Resp_CityAcc_upd_cmp = 100;

            int TipoCompyCode = 0;

            Guid ContactoId = Guid.Empty;
            Guid PropietarioId = Guid.Empty;     
            
            // 2 Septimembre 2014
            Guid EmpresaInplantAsId = Guid.Empty;
            Guid EmpresaMatrizId = Guid.Empty;

            Entity UsrProp = null;

            string CodigoCompy = string.Empty;

            // 2 Septimembre 2014
            string CodigoCompyMtz = string.Empty;

            string NombreEmp = string.Empty;
            string Calle = string.Empty;
            string NumExt = string.Empty;
            string NumInt = string.Empty;
            string Colonia = string.Empty;
            string DelegMun = string.Empty;
            string Ciudad = string.Empty;
            string Direccion = string.Empty;
            string Estado = string.Empty;
            string CodigoPostal = string.Empty;
            string Pais = string.Empty;
            string Telefono = string.Empty;
            string Rfc = string.Empty;
            string ClaseComp = string.Empty;
            string TipoComp = string.Empty;
            string EstatusComp = string.Empty;
            string TipoDir = string.Empty;
            string ArcCodeCxC = string.Empty;          
            string Comp_mtz_code = string.Empty;

            string NombreDom = string.Empty;
            string Iata = string.Empty;

            string TipoCompySetPers = string.Empty;


            bool ContactoActualizado = false;
            bool MatrizActualizada = false;

            BasicHttpBinding CityAccess_bin = new BasicHttpBinding();
            CityAccess_bin.Name = "CityAccessWSSoap";
            EndpointAddress EndPointCityAccess = new EndpointAddress("http://wshc.hotelescity.com:9742/CityHubV28Pruebas/CityAccessWS.asmx");

            #region WCF Para transacciones (Decartado)
            //WSHttpBinding CityAccess_bin = new WSHttpBinding();
            //CityAccess_bin.Name = "WSHttpBinding_ICityAccessServices";
            //CityAccess_bin.TransactionFlow = true;
            //EndpointAddress EndPointCityAccess = new EndpointAddress("http://wshc.hotelescity.com:9742/CityHubV28Pruebas/CityAccessServices.svc");
            #endregion

            #endregion

            #region Tratamiento Información de Empresa
            try
            {             

                // Recupera Información de la Empresa y se realiza el tratamiento de la misma
                CodigoCompy = Empresa.Attributes.Contains("accountnumber") ? Empresa.Attributes["accountnumber"].ToString() : "";
                NombreEmp = Empresa.Attributes.Contains("name") ? Empresa.Attributes["name"].ToString() : "";
                Calle = Empresa.Attributes.Contains("address1_line1") ? Empresa.Attributes["address1_line1"].ToString() : "";
                NumExt = Empresa.Attributes.Contains("new_nmeroexterior") ? Empresa.Attributes["new_nmeroexterior"].ToString() : "";
                NumInt = Empresa.Attributes.Contains("new_interior") ? Empresa.Attributes["new_interior"].ToString() : "";
                Colonia = Empresa.Attributes.Contains("new_coloniaid") ? ((EntityReference)Empresa.Attributes["new_coloniaid"]).Name : "";
                DelegMun = Empresa.Attributes.Contains("new_delegacionmunicipioid") ? ((EntityReference)Empresa.Attributes["new_delegacionmunicipioid"]).Name : "";
                Ciudad = Empresa.Attributes.Contains("new_ciudadid") ? ((EntityReference)Empresa.Attributes["new_ciudadid"]).Name : "";
                Direccion = String.Format("{0} {1} {2} {3} {4} {5}  ", Calle, NumExt, NumInt, Colonia, DelegMun, Ciudad);
                Estado = Empresa.Attributes.Contains("new_estadoid") ? ((EntityReference)Empresa.Attributes["new_estadoid"]).Name : "";
                CodigoPostal = Empresa.Attributes.Contains("address1_postalcode") ? Empresa.Attributes["address1_postalcode"].ToString() : "";
                Pais = MetodosFes.RecuperaClavePais(Empresa.Attributes.Contains("new_paisid") ? ((EntityReference)Empresa.Attributes["new_paisid"]).Id : Guid.Empty);
                Telefono = Empresa.Attributes.Contains("new_telefono") ? Empresa.Attributes["new_telefono"].ToString() : "";
                Telefono = System.Text.RegularExpressions.Regex.Replace(Telefono, "[^0-9]", "");
                Rfc = Empresa.Attributes.Contains("new_rfc") ? Empresa.Attributes["new_rfc"].ToString() : "";
                ClaseComp = MetodosFes.RecuperaDescripcionOs("account", "new_clasecompy", 279640000); //"COR";                         
                
                //TipoComp = Empresa.Attributes.Contains("new_tipocompy") ? Empresa.FormattedValues["new_tipocompy"].ToString() : "";                
                // 1ero de Septiembre 2014 . Cambio relacionado a las agencias Matriz y Agencias de tipo inplant             
                TipoCompyCode = Empresa.Attributes.Contains("new_tipocompy") ? ((OptionSetValue)Empresa.Attributes["new_tipocompy"]).Value : 0;
                // Recuperamos la descripción del Pickist del tipo de Compañia
                TipoComp = MetodosFes.RecuperaDescripcionOs("account", "new_tipocompy", TipoCompyCode);
 
                EstatusComp = Empresa.Attributes.Contains("statuscode") ? Empresa.FormattedValues["statuscode"].ToString() : ""; //"Activo";
                TipoDir = MetodosFes.RecuperaDescripcionOs("account", "new_tipodircompy", 279640000); //"Perm"; 
                ArcCodeCxC = Empresa.Attributes.Contains("new_codigocxc") ? Empresa.FormattedValues["new_codigocxc"].ToString() : ""; //".";  
                PropietarioId = Empresa.Attributes.Contains("ownerid") ? ((EntityReference)Empresa.Attributes["ownerid"]).Id : Guid.Empty;
                Iata = Empresa.Attributes.Contains("new_iata") ? Empresa.Attributes["new_iata"].ToString() : "";

                EmpresaMatrizId = Empresa.Attributes.Contains("parentaccountid") ? ((EntityReference)Empresa.Attributes["parentaccountid"]).Id : Guid.Empty;

                // Recuperamos el ID de la Empresa Asociada (Agencia Matriz (3)) o InPlant (Empresa Inplant(2))
                EmpresaInplantAsId = Empresa.Attributes.Contains("new_empresainplant") ? ((EntityReference)Empresa.Attributes["new_empresainplant"]).Id : Guid.Empty;

                // Recuperamos el dato, sobre si fue actualizado el contacto desde el formulario
                ContactoActualizado = Empresa.Attributes.Contains("new_contactoactualizado") ? (bool)Empresa.Attributes["new_contactoactualizado"] : false;

                // 19 Septiembre Si la empresa matriz se actualizó desde el formulario
                MatrizActualizada = Empresa.Attributes.Contains("new_matrizactualizada") ? (bool)Empresa.Attributes["new_matrizactualizada"] : false;

                // Si la IATA trae un dato, entonces el ArcCode debe de ir en blanco
                if (Iata != "")
                    ArcCodeCxC = "";

                #region Tratamiento en caso de ser Una empresa Hija
                
                if (EmpresaMatrizId != Guid.Empty)
                {
                    Entity Emp_Hija = Serv.Retrieve("account", EmpresaMatrizId, new ColumnSet("accountnumber"));
                    if (MetodosFes.ExisteAtributo("accountnumber", Emp_Hija))
                        Comp_mtz_code = (string)Emp_Hija.Attributes["accountnumber"];
                }

                #endregion

                #region 1 Septiembre 2014  Recuperación Comp_Code Empresa Inplant
                // Si la empresa es Agencia Inplant o Agencia Matriz
                if (TipoCompyCode.Equals(2) || TipoCompyCode.Equals(3))
                {                    
                    // Validamos que exista un Guid del campo de busqueda Empresa Asociada(Agencia Matriz) o Empresa Inplant
                    if (EmpresaInplantAsId != Guid.Empty)
                    {
                        // Recuperamos el Código de compañia de la empresa que tiene una agencia Inplant
                        Entity EmpresaIn = Serv.Retrieve("account", EmpresaInplantAsId, new ColumnSet("accountnumber"));
                        // Se lo asignamos al Código de Compañía
                        CodigoCompy = EmpresaIn.Attributes.Contains("accountnumber") ? EmpresaIn.Attributes["accountnumber"].ToString() : "";
                    }
                }                          
                #endregion 

                #region Tratamiento Para enviarle al SetPersonToCompany si es A o C
                // Si la compañia es de tipo Inplant se manda como A
                /*19 De Sept HC define cambio, ahora tambien las agencias matrices son de tipo A*/
                if (TipoCompyCode.Equals(2) || TipoCompyCode.Equals(3))
                {
                    TipoCompySetPers = "A";           
                }
                else
                {
                    TipoCompySetPers = "C";
                }
                #endregion

                #region Tratamiento Propietario

                if (PropietarioId != Guid.Empty)
                {
                    UsrProp = Serv.Retrieve("systemuser", PropietarioId, new ColumnSet("domainname", "new_nombref2g")); // Cambio 26 Julio por nuevo campo
                    //if (MetodosFes.ExisteAtributo("domainname", UsrProp))
                    if (MetodosFes.ExisteAtributo("new_nombref2g", UsrProp))
                    {
                        NombreDom = (string)UsrProp.Attributes["new_nombref2g"];
                        //NombreDom = MetodosFes.DevuelveNombre(NombreDom);
                    }
                }
                #endregion
            }
            catch (Exception ex)
            {
                throw new InvalidPluginExecutionException("Hoteles City ERROR CRM Tratamiento Información de Empresa para Integración F2G-CityAccess. " + ex.Message);
            }
            #endregion

            // Inicializamos la variable de la transaccion para City Access (DESCARTADO **)
            //using (TransactionScope TsCa = new TransactionScope()) 
          
            CityAccessWSSoapClient Cliente_CityAcc = new CityAccessWSSoapClient(CityAccess_bin, EndPointCityAccess);

            #region INSERT - INTEGRACION F2G - CITY ACCESS
            // Verificamos que el mensaje sea de Creación
            if (Mensaje.Equals("Create"))
            {
                // Envía Información de Empresa a Front2Go
                Resp_Front_ins_cmp = Cliente_Front2Go.Insert_cmpy(NombreEmp, ClaseComp, TipoComp, CodigoCompy, Comp_mtz_code, EstatusComp, TipoDir, "", "", Pais, Direccion, CodigoPostal, ArcCodeCxC, Telefono, Rfc, Iata, "", NombreDom);

                /*ERROR F2G - PARAR PROCESO */
                if (Resp_Front_ins_cmp < 0)
                    throw new InvalidPluginExecutionException("Hoteles City ERROR de Integración Front2GO. No se pudo Insertar la Empresa a Front2Go. Código de error: " + Resp_Front_ins_cmp.ToString() + " Detalle: " + MetodosFes.DetalleError(Resp_Front_ins_cmp, 1));
                
                if (Resp_Front_ins_cmp > 0)
                {
                    try
                    {
                        if (TipoCompyCode.Equals(2) || TipoCompyCode.Equals(3))                                               
                            Rfc = "";                       

                        // Si es correcto el envío, se envía Empresa a City Access       
                        Resp_CityAcc_ins_cmp = Cliente_CityAcc.Insert_cmpy(NombreEmp, ClaseComp, TipoComp, CodigoCompy, Comp_mtz_code, EstatusComp, TipoDir, Ciudad, Estado, Pais, Direccion, CodigoPostal, ArcCodeCxC, Telefono, Rfc, Iata, "");
                    }
                    catch (Exception ex)
                    {
                        /*ELIMINA EMPRESA F2G */
                        MetodosFes.EliminaF2GCompy(Resp_Front_ins_cmp, CodigoCompy, NombreDom, Guid.Empty, Cliente_Front2Go);
                        throw new InvalidPluginExecutionException("Hoteles City ERROR de Integración CityAccess. Error al consumir el contrato Insert_Compy. Detalle de error: " + ex.Message);
                    }

                    /*ERROR CITY ACCESS - PARAR PROCESO */
                    if (Resp_CityAcc_ins_cmp < 0)
                    {
                        /*ELIMINA EMPRESA F2G */
                        MetodosFes.EliminaF2GCompy(Resp_Front_ins_cmp, CodigoCompy, NombreDom, Guid.Empty, Cliente_Front2Go);
                        throw new InvalidPluginExecutionException("Hoteles City ERROR de Integración CityAccess. No se pudo Insertar la Empresa a City Access. Código de error: " + Resp_CityAcc_ins_cmp.ToString() + " .Detalle: " + MetodosFes.DetalleError(int.Parse(Resp_CityAcc_ins_cmp.ToString()), 2));
                    }

                    #region FRONT2GO - SetPersonToCompany Integración Enrola Contacto a Cuenta
                    AsignaContactoDesdeEmpresa(Mensaje, Cliente_Front2Go, Cliente_Prop, Cliente_CityAcc, Empresa, CodigoCompy, Resp_CityAcc_ins_cmp, Serv, Resp_Front_ins_cmp, NombreDom, TipoCompySetPers);
                    #endregion                 
                }                           
            }
            #endregion

            #region UPDATE - INTEGRACION F2G - CITY ACCESS

            // Verificamos que el mensaje sea de Actualización
            if (Mensaje.Equals("Update"))
            {
                // Recuperamos el valor del ID de la inserción de la empresa en City Access
                Resp_CityAcc_ins_cmp = Empresa.Attributes.Contains("new_resp_ca_ins_cmp") ? (int)Empresa.Attributes["new_resp_ca_ins_cmp"] : 0; 

                #region Nuevo Req. 1 Septiembre. Eliminar / Asociar Relación entre empresa suc y matriz 
                // Si es una empresa Hija con su Emrpesa Matriz
                if (EmpresaMatrizId != Guid.Empty && MatrizActualizada) // 19 Setp Se agrega código para tomar en cuenta si la matriz fue actualizada desde el formulario
                {        
                    string Resp_ElimRelMtz = string.Empty;
                    string Resp_AsoRelMtz = string.Empty;

                    // Eliminamos la relación, con su código compy de la empresa hija y el tipo "C" o "A"
                    Resp_ElimRelMtz = Cliente_Front2Go.EliminaRelacionMatriz(CodigoCompy, TipoCompySetPers);

                    // Si se eliminó correctamente la relación
                    if (Resp_ElimRelMtz.Equals("0 - Exitoso"))
                    {
                        // Realizamos la asociación de la nueva empresa Matriz
                        Resp_AsoRelMtz = Cliente_Front2Go.AsociaMatriz(Comp_mtz_code, CodigoCompy, TipoCompySetPers);

                        // Si hay error en la asociación, entonces detenemos el proceso
                        if (Resp_AsoRelMtz != "0 - Exitoso")
                            throw new InvalidPluginExecutionException("F2G Integración. No se pudo asociar con la empresa Matriz. Código de error: " + Resp_AsoRelMtz + " Detalle: " + MetodosFes.DetalleError(Resp_Front_upd_cmp, 3));
                    }
                    else
                        throw new InvalidPluginExecutionException("F2G Integración. No se pudo eliminar la relación con la empresa Matriz. Código de error: " + Resp_ElimRelMtz + " Detalle: " + MetodosFes.DetalleError(Resp_Front_upd_cmp, 3));
                }
                #endregion

                // Nota: Si se actualiza la empresa Matriz, no se debe de enviar nuevamente el mtz_compcode

                #region Actualiza Información de Empresa a Front2Go 
                Resp_Front_upd_cmp = Cliente_Front2Go.Update_cmpy(NombreEmp, ClaseComp, TipoComp, CodigoCompy, Comp_mtz_code, EstatusComp, TipoDir, "MX", Direccion, CodigoPostal, ArcCodeCxC, Telefono, Rfc, Iata, "", NombreDom);

                if (Resp_Front_upd_cmp.Equals(0))
                {
                    // 07 Noviembre 2014 - HC solicita pasar código de compañia al RFC (Sólo Update)
                    //if (TipoCompyCode.Equals(2) || TipoCompyCode.Equals(3))
                        Rfc = CodigoCompy;      

                    // Si es correcto el envío, Actualiza Informacion de empresa a City Access  
                    Resp_CityAcc_upd_cmp = Cliente_CityAcc.Update_cmpy(NombreEmp, ClaseComp, TipoComp, CodigoCompy, Comp_mtz_code, EstatusComp, TipoDir, Ciudad, Estado, Pais, Direccion, CodigoPostal, ArcCodeCxC, Telefono, Rfc, Iata, Rfc, NombreDom);
                }

                if (Resp_Front_upd_cmp != 0)
                    throw new InvalidPluginExecutionException("Hoteles City ERROR de Integración. No se pudo Actualizar la Empresa a Front2Go. Código de error: " + Resp_Front_upd_cmp.ToString() + " Detalle: " + MetodosFes.DetalleError(Resp_Front_upd_cmp, 3));

                if (Resp_CityAcc_upd_cmp != 0)
                    throw new InvalidPluginExecutionException("Hoteles City ERROR de Integración. No se pudo Actualizar la Empresa a City Access. Código de error: " + Resp_CityAcc_upd_cmp.ToString() + " Detalle: " + MetodosFes.DetalleError(Resp_CityAcc_upd_cmp, 4)); 
                #endregion

                #region SetPersonToCompany - Actualizacion de Contacto        
                // Si hay actualizacion
                if (ContactoActualizado)
                {
                    #region FRONT2GO - SetPersonToCompany Integración Enrola Contacto a Cuenta
                    AsignaContactoDesdeEmpresa(Mensaje, Cliente_Front2Go, Cliente_Prop, Cliente_CityAcc, Empresa, CodigoCompy, Resp_CityAcc_ins_cmp, Serv, Resp_Front_ins_cmp, NombreDom, TipoCompySetPers);
                    #endregion
                }                
                #endregion
            }
            #endregion

            #region Actualización de estados en CRM
            try
            {
                Entity ActEdoInte = new Entity("account");
                ActEdoInte.Attributes["accountid"] = EmpresaId;

                if (Mensaje.Equals("Create"))
                {
                    ActEdoInte.Attributes["new_resp_ftg_ins_cmp"] = Resp_Front_ins_cmp;
                    ActEdoInte.Attributes["new_resp_ca_ins_cmp"] = Resp_CityAcc_ins_cmp;

                    /*1 Septiembre 2014  Actualizamos el código de compañía, siempre y cuando sea Tipo Agencia Inplant*/
                    if (TipoCompyCode.Equals(2) || TipoCompyCode.Equals(3))
                        ActEdoInte.Attributes["accountnumber"] = CodigoCompy;
                }

                if (Mensaje.Equals("Update"))
                {                   
                    ActEdoInte.Attributes["new_resp_ftg_upd_cmp"] = Resp_Front_upd_cmp;  
                    ActEdoInte.Attributes["new_resp_ca_upd_cmp"] = Resp_CityAcc_upd_cmp;
                    // Regresamos la bandera de contacto actualizado a su estado normal
                    ActEdoInte.Attributes["new_contactoactualizado"] = false;
                    // 06 Oct 2014 Regresamos bandera a su estado inicial
                    ActEdoInte.Attributes["new_matrizactualizada"] = false;                    
                }

                Serv.Update(ActEdoInte);              
            }
            catch (Exception ex)
            {
                if (Mensaje.Equals("Create"))
                {
                    /*Elimina Empresa Creada en F2G*/
                    MetodosFes.EliminaF2GCompy(Resp_Front_ins_cmp, CodigoCompy, NombreDom, Guid.Empty,Cliente_Front2Go);
                    /* Se elimina la empresa de City Access */
                    MetodosFes.EliminaCityAccCompy(CodigoCompy, Guid.Empty,Cliente_CityAcc);
                }
                throw new InvalidPluginExecutionException("Hoteles City ERROR CRM Actualización de estados en Formulario Empresas. " + ex.Message);
            }
            #endregion                 
        }
        #endregion

        // Funcion que enrola un contacto a una empresa, se manda llamar en la creación y en la actualización 
        private void AsignaContactoDesdeEmpresa(string Msj, ws_PerfilesSoapClient Cliente_Front2Go, ws_ConveniosSoapClient Cliente_Prop, CityAccessWSSoapClient Cliente_CityAcc, Entity Empresa, string Code_com, int Id_Cmpy_ca,IOrganizationService Serv, int SelloEmp, string UsrDom, string TipoCompyCode)
        {
            Guid ContactoId = Guid.Empty;
            Guid EmpId = Guid.Empty;
            //int Resp_CityAcc_SetPersonComp = 100;
            int TipoPers = 0;
            string Relacion = "PRINCIPAL";
            int IdContac_Ca = 0;

            cRespuestaAsociacion RespAso_F2G = null;
            Resultado Resp_CityAcc_SetPersonComp = null;

            // Recuperamos el Contacto que trae la empresa
            if (MetodosFes.ExisteAtributo("primarycontactid", Empresa))
                ContactoId = ((EntityReference)Empresa.Attributes["primarycontactid"]).Id;

            // Recuperamos la empresa que trae el contacto
            if (MetodosFes.ExisteAtributo("accountid", Empresa))
                EmpId = (Guid)Empresa.Attributes["accountid"];


            // Si existe, entonces recuperamos su Email y mandamos enrolarlo a la cuenta
            if (ContactoId != Guid.Empty)
            {
                Entity Con = Serv.Retrieve("contact", ContactoId, new ColumnSet("emailaddress1","new_resp_ca_ins_guest", "new_tipopersona"));

                // Recuperamos el tipo de Persona 5: "CONTACTO"    
                if (MetodosFes.ExisteAtributo("new_tipopersona", Con))
                {
                    TipoPers = ((OptionSetValue)Con.Attributes["new_tipopersona"]).Value;
                    // Si el tipo No es "Contacto", no permtimos continuar con el proceso
                    if (!TipoPers.Equals(5))
                        throw new InvalidPluginExecutionException("Front2Go SetPersonToCompany. No se puede asociar la persona, porque el tipo NO es Contacto");
                }

                // Recuperamos el ID del Guest en caso de que exista
                if (MetodosFes.ExisteAtributo("new_resp_ca_ins_guest", Con))
                {
                    IdContac_Ca = (int)Con.Attributes["new_resp_ca_ins_guest"];
                }

                if (MetodosFes.ExisteAtributo("emailaddress1", Con))
                {
                    string Correo = (string)Con.Attributes["emailaddress1"];              

                    try
                    {
                        // FRONT2GO -  Mandamos llamar el metodo que asocia el contacto, Siempre y cuando la Empresa haya sido creada correctamente
                        RespAso_F2G = Cliente_Prop.SetPersonToCompany(Code_com, Correo, Relacion, TipoCompyCode);
                    }
                    catch (Exception ex)
                    {
                        /*Si el mensaje es en la creación, entonces elimina la Empresa EN F2G y CA*/
                        if (Msj.Equals("Create"))
                        {
                            MetodosFes.EliminaF2GCompy(SelloEmp, Code_com, UsrDom, Guid.Empty, Cliente_Front2Go);
                            /* ROLLBACK INSERCION DE EMPRESA CA*/
                            MetodosFes.EliminaCityAccCompy(Code_com, Guid.Empty, Cliente_CityAcc);
                        }

                        throw new InvalidPluginExecutionException("Front2Go SetPersonToCompany (Empresa). Error al consumir el método. Detalle: " + ex.Message);
                    }

                    // Error SetPersonToCompany ** Dejamos correr el proceso, debido a que si no se asocia, se puede asociar más tarde.
                    if (!RespAso_F2G.AsociacionCorrecta)
                    {
                        /*Si el mensaje es en la creación, entonces elimina la Empresa EN F2G y CA*/
                        if (Msj.Equals("Create"))
                        {
                            MetodosFes.EliminaF2GCompy(SelloEmp, Code_com, UsrDom, Guid.Empty, Cliente_Front2Go);
                            /* ROLLBACK INSERCION DE EMPRESA CA*/
                            MetodosFes.EliminaCityAccCompy(Code_com, Guid.Empty, Cliente_CityAcc);
                        }

                        /* Mostramos la excepción */
                        throw new InvalidPluginExecutionException("Front2Go SetPersonToCompany (Empresa). La asociación no se realizó correctamente debido a: " + RespAso_F2G.DescError);
                    }

                    // Si la respuesta del servicio de Front2Go fue correcta y existe el ID de Compy y Guest enviamos la relación a City Access
                    if (RespAso_F2G.AsociacionCorrecta && Id_Cmpy_ca > 0 && IdContac_Ca > 0)
                        Resp_CityAcc_SetPersonComp = Cliente_CityAcc.SetPersonToCompany(Relacion, Id_Cmpy_ca, IdContac_Ca);

                    if (int.Parse(Resp_CityAcc_SetPersonComp.Codigo) < 0)
                    {
                        /*Si es en la creación de la empresa y hay error, entonces sí elimina la empresa en F2G y CA*/
                        if (Msj.Equals("Create"))
                        {
                            MetodosFes.EliminaF2GCompy(SelloEmp, Code_com, UsrDom, Guid.Empty, Cliente_Front2Go);
                            /* ROLLBACK INSERCION DE EMPRESA CA*/
                            MetodosFes.EliminaCityAccCompy(Code_com, Guid.Empty, Cliente_CityAcc);
                        }

                        throw new InvalidPluginExecutionException("City Access SetPersonToCompany (Empresa). La asociación no se realizó correctamente. Descripción del Error: " + Resp_CityAcc_SetPersonComp.Descripcion.ToString());
                    }

                }
                else
                {
                    if (Msj.Equals("Create"))
                    {
                        /*ROLLBACK INSERCION DE EMPRESA F2G*/
                        MetodosFes.EliminaF2GCompy(SelloEmp, Code_com, UsrDom, Guid.Empty, Cliente_Front2Go);
                        /* ROLLBACK INSERCION DE EMPRESA CA*/
                        MetodosFes.EliminaCityAccCompy(Code_com, Guid.Empty, Cliente_CityAcc);
                    }
                    throw new InvalidPluginExecutionException("Front2Go SetPersonToCompany (Empresa). El contacto no cuenta con dirección de correo electrónico, no se puede asociar a la Empresa.");
                }
            }           
        }
    }

    /// <summary>
    /// Autor: Julio Esquivel 
    /// Fecha Junio 2014
    /// Descripción: Integración con F2G y City Access.
    /// Entidad: Contacto (contact)
    /// Métodos: Create, Update. 
    /// Contratos: Insert_guest, Update_guest
    /// </summary>
    /// 
    public class IntegraContacto : IPlugin
    {
        public void Execute(IServiceProvider ProveedorServicio)
        {
            
                #region Consumo de Servicio de Organización y Variables de Contexto del plugin
                // Limpiamos objetos de entidad y WS
                Entity Entidad = null;
                IOrganizationService Servicio = null;

                //Obtenemos el Contexto de ejecución del Plugin
                IPluginExecutionContext Contexto = (IPluginExecutionContext)ProveedorServicio.GetService(typeof(IPluginExecutionContext));

                // Validamos que exista un objeto de tipo Entity
                Entidad = ValidaContexto(Contexto, ProveedorServicio);

                try 
                {
                // Consumimos el Servicio de Organización      
                    Servicio = OrganizationServiceCrm.ObtenerServicioCallingUser(Contexto, ProveedorServicio);
                    // Pasamos Objeto de Servicio a los métodos FesXrm
                    MetodosFes InicializaServicio = new MetodosFes(Servicio);
                }
                catch (FaultException<OrganizationServiceFault> ex)
                {
                    throw new InvalidPluginExecutionException("Hoteles City ERROR CRM Consumo de Servicios de Organización. " + ex.Message);
                }
                #endregion

                #region Configuracion de WS 
                // Configuramos Binding de Servicios
                BasicHttpBinding Front2Go_bin = new BasicHttpBinding();     
                BasicHttpBinding AsignaProp_bin = new BasicHttpBinding();

                Front2Go_bin.Name = "ws_PerfilesSoap";               
                AsignaProp_bin.Name = "ws_ConveniosSoap";

                EndpointAddress EndPointFront2Go = new EndpointAddress("http://200.79.228.19/whsEngine/ws_Perfiles.asmx");
                EndpointAddress EndPointAsignProp = new EndpointAddress("http://200.79.228.19/whsEngine/ws_Convenios.asmx");

                // Instanciamos el objeto de los servicios                                    
                ws_PerfilesSoapClient Cliente_F2G = new ws_PerfilesSoapClient(Front2Go_bin, EndPointFront2Go);           
                ws_ConveniosSoapClient Cliente_Conve = new ws_ConveniosSoapClient(AsignaProp_bin, EndPointAsignProp);
                #endregion

                #region Proceso Principal que invoca la Integración de Empresa
                // Validamos que la entidad realmente sea Contacto
                if (Contexto.PrimaryEntityName.Equals("contact"))
                {
                    // Objeto entidad con que cotendrá la información de la Empresa
                    Entity Contact = null;
                    //EntityCollection Contactos_dup = null;

                    // Recuperamos los datos del Contacto por el Guid
                    Contact = Servicio.Retrieve("contact", Contexto.PrimaryEntityId, new ColumnSet("firstname", "lastname", "new_tipopersona", "new_titulo", "telephone1", "emailaddress1", "new_paisid", "address1_line1", "new_nmeroexterior",
                                                                                                   "new_nmerointerior", "new_coloniaid", "ownerid", "parentcustomerid", "new_frqtvl_codigo", "new_pfreqtvl_num", "originatingleadid", "new_resp_ca_ins_guest")); 
                    
                    // Validamos duplicados 
                    //if (MetodosFes.ExisteAtributo("emailaddress1", Contact))
                    //{
                        // Verificamos si ya existe en la BD de CRM un contacto con el mismo correo electrónico (Activos/Inactivos) (A Excepcion del actual)
                        //Contactos_dup = MetodosFes.RecuperacionMultipleNot("contact", new string[] { "contactid" }, "emailaddress1", (string)Contact.Attributes["emailaddress1"], "contactid", Contexto.PrimaryEntityId.ToString());

                        // Si hay más de un contacto coincidente (considerando el actual), entonces realizamos la integracion

                        //if (Contactos_dup.Entities.Equals(0))
                        //{
                            // Se manda llamar método que realiza la Integración
                            InsUpdContacto(Contact, Contexto.MessageName, Servicio, Contexto.PrimaryEntityId, Cliente_F2G, Cliente_Conve, Entidad);
                        //}
                        //else
                        //{
                          //  return;
                        //}
                    //}
                }
                #endregion
        }

        #region # Método de validación del Contexto que recibe el Plugin
        private Entity ValidaContexto(IPluginExecutionContext Context, IServiceProvider Prov_Servicio)
        {
            Entity Ent = null;

            if (Context.InputParameters.Contains("Target") && Context.InputParameters["Target"] is Entity)
                Ent = (Entity)Context.InputParameters["Target"];

            return Ent;
        }
        #endregion

        private void InsUpdContacto(Entity Contacto, string Mensaje, IOrganizationService Serv, Guid ContactoId, ws_PerfilesSoapClient Cliente_Front2Go, ws_ConveniosSoapClient Cliente_Prop, Entity EntContexto)
        {
            #region Declaración de Variables Locales

            int Resp_Front_ins_guest = 0;
            //Resultado Resp_CityAcc_ins_guest = null;
            int Resp_CityAcc_ins_guest = 100;
            string Resp_Front_upd_guest = "NO DATOS";
            int Resp_CityAcc_upd_guest = 100;

            int TipoPersona_co = 0;
            string Nombres_co = string.Empty;
            string Apellidos_co = string.Empty;
            string Titulo_co = string.Empty;
            string Tel_co = string.Empty;
            string Email = string.Empty;
            string ClasePer = string.Empty;
            int EstatusPerContacto = 0;
            string TipoDir_co = string.Empty;
            string Pais_co = string.Empty;
            string NombreDom = string.Empty;
            string Frqtvl = string.Empty;

            string Calle = string.Empty;
            string NumExt = string.Empty;
            string NumInt = string.Empty;
            string Colonia = string.Empty;
            string Direccion = string.Empty;

            int Frqtvl_codigo = 0;
            string Frqtvl_num = string.Empty;

            bool EsPrincipal = false;

            Guid PropietarioId = Guid.Empty;
            Entity UsrProp = null;

            Guid Lead_originId = Guid.Empty;

            BasicHttpBinding CityAccess_bin = new BasicHttpBinding();
            CityAccess_bin.Name = "CityAccessWSSoap";
            EndpointAddress EndPointCityAccess = new EndpointAddress("http://wshc.hotelescity.com:9742/CityHubV28Pruebas/CityAccessWS.asmx");

            #region WCF Para transacciones (DESCARTADO)
            //WSHttpBinding CityAccess_bin = new WSHttpBinding();
            //CityAccess_bin.Name = "WSHttpBinding_ICityAccessServices";
            //CityAccess_bin.TransactionFlow = true;
            //EndpointAddress EndPointCityAccess = new EndpointAddress("http://wshc.hotelescity.com:9742/CityHubV28Pruebas/CityAccessServices.svc");
            #endregion

            #endregion

            #region Tratamiento Información de Contacto / Huesped

            try
            {
                /*JER 12 AGOSTO 2014 - Para conocer si el flujo de creación es desde prospecto */
                Lead_originId = Contacto.Attributes.Contains("originatingleadid") ? ((EntityReference)Contacto.Attributes["originatingleadid"]).Id : Guid.Empty;

                TipoPersona_co = Contacto.Attributes.Contains("new_tipopersona") ? ((OptionSetValue)Contacto.Attributes["new_tipopersona"]).Value : 0;
                /*JER 11 AGOSTO TODOS LOS QUE SE CREEN, SERAN CONTACTOS */
                TipoPersona_co = 5;

                Nombres_co = Contacto.Attributes.Contains("firstname") ? (string)Contacto.Attributes["firstname"] : "";
                Apellidos_co = Contacto.Attributes.Contains("lastname") ? (string)Contacto.Attributes["lastname"] : "";
                Titulo_co = Contacto.Attributes.Contains("new_titulo") ? Contacto.FormattedValues["new_titulo"].ToString() : "";
                Titulo_co = Titulo_co.Replace(".", "");
                Tel_co = Contacto.Attributes.Contains("telephone1") ? (string)Contacto.Attributes["telephone1"] : "";
                Tel_co = System.Text.RegularExpressions.Regex.Replace(Tel_co, "[^0-9]", "");

                Calle = Contacto.Attributes.Contains("address1_line1") ? Contacto.Attributes["address1_line1"].ToString() : "";
                NumExt = Contacto.Attributes.Contains("new_nmeroexterior") ? Contacto.Attributes["new_nmeroexterior"].ToString() : "";
                NumInt = Contacto.Attributes.Contains("new_interior") ? Contacto.Attributes["new_nmerointerior"].ToString() : "";
                Colonia = Contacto.Attributes.Contains("new_coloniaid") ? ((EntityReference)Contacto.Attributes["new_coloniaid"]).Name : "";              
                Direccion = String.Format("{0} {1} {2} {3} ", Calle, NumExt, NumInt, Colonia);

                Email = Contacto.Attributes.Contains("emailaddress1") ? (string)Contacto.Attributes["emailaddress1"] : "";
                ClasePer = MetodosFes.RecuperaDescripcionOs("contact", "new_clasepersona", 279640000); //"CUS";  
                EstatusPerContacto = 4; // Estará Activo siempre en la creación
                TipoDir_co = MetodosFes.RecuperaDescripcionOs("contact", "new_tipodirpersona", 279640000); //"Perm"; new_tipodirpersona
                Pais_co = MetodosFes.RecuperaClavePais(Contacto.Attributes.Contains("new_paisid") ? ((EntityReference)Contacto.Attributes["new_paisid"]).Id : Guid.Empty);
                PropietarioId = Contacto.Attributes.Contains("ownerid") ? ((EntityReference)Contacto.Attributes["ownerid"]).Id : Guid.Empty;
                //EsPrincipal = Contacto.Attributes.Contains("new_esprincipal") ? (bool)Contacto.Attributes["new_esprincipal"] : false;

                /*17 Julio Se agrega campos de Tipo de Programa y numero de cliente frecuente */             
                // Recuperamos Código seleccionado del tipo de programa
                Frqtvl_codigo = Contacto.Attributes.Contains("new_frqtvl_codigo") ? ((OptionSetValue)Contacto.Attributes["new_frqtvl_codigo"]).Value : 0;                
                Frqtvl = (Frqtvl_codigo > 0) ? MetodosFes.RecuperaDescripcionOs("contact", "new_frqtvl_codigo", Frqtvl_codigo) : "";
                // Recuperamos el numero de cliente frecuente
                Frqtvl_num = Contacto.Attributes.Contains("new_pfreqtvl_num") ? (string)Contacto.Attributes["new_pfreqtvl_num"] : "";  

                #region Tratamiento Propietario

                if (PropietarioId != Guid.Empty)
                {
                    UsrProp = Serv.Retrieve("systemuser", PropietarioId, new ColumnSet("domainname", "new_nombref2g"));
                    //if (MetodosFes.ExisteAtributo("domainname", UsrProp))
                    if (MetodosFes.ExisteAtributo("new_nombref2g", UsrProp))
                    {
                        NombreDom = (string)UsrProp.Attributes["new_nombref2g"];
                        //NombreDom = MetodosFes.DevuelveNombre(NombreDom);
                    }
                }
                #endregion
            }
            catch (Exception ex)
            {
                throw new InvalidPluginExecutionException("Hoteles City ERROR CRM Tratamiento Información de Contacto para Integración F2G-City Access. " + ex.Message);
            }

            #endregion

            // Inicializamos la variable de la transaccion para City Access (DESCARTADO)
            //using (TransactionScope TsCa = new TransactionScope())
            
            CityAccessWSSoapClient Cliente_CityAcc = new CityAccessWSSoapClient(CityAccess_bin, EndPointCityAccess);

            #region INSERT - INTEGRACION F2G - CITY ACCESS
            // Verificamos que el mensaje sea de Creación
            if (Mensaje.Equals("Create"))
            {
                // Insertamos Contacto / Huesped a Front2Go
                Resp_Front_ins_guest = Cliente_Front2Go.Insert_guest(TipoPersona_co, Apellidos_co, Nombres_co, Titulo_co, Tel_co, Email, ClasePer, EstatusPerContacto.ToString(), Frqtvl_num, Frqtvl, TipoDir_co, "", "", Pais_co, Direccion, "0", NombreDom);

                if (Resp_Front_ins_guest < 0)
                {
                    // (Si viene de flujo Prospecto) Elimina las empresas en caso de error en la inserción del contacto a F2G 
                    if (Lead_originId != Guid.Empty)
                    {
                        // Elimina Empresa F2G 
                        MetodosFes.EliminaF2GCompy(0, string.Empty, NombreDom, ContactoId, Cliente_Front2Go);
                        // Elimina Empresa CA
                        MetodosFes.EliminaCityAccCompy(string.Empty, ContactoId, Cliente_CityAcc);
                    }

                    throw new InvalidPluginExecutionException("Hoteles City ERROR de Integración Front2Go. No se pudo Insertar el Contacto a Front2Go. Código de error: " + Resp_Front_ins_guest.ToString() + " Detalle: " + MetodosFes.DetalleError(Resp_Front_ins_guest, 5));
                }

                if (Resp_Front_ins_guest > 0)
                {
                    try
                    {
                        // Insertamos Contacto / Huesped a CityAcccess
                        Resp_CityAcc_ins_guest = Cliente_CityAcc.Insert_guest(TipoPersona_co.ToString(), Apellidos_co, Nombres_co, Titulo_co, Tel_co, Email, ClasePer, EstatusPerContacto.ToString(), Frqtvl_num, Frqtvl, TipoDir_co, "", "", Pais_co, Direccion, "0", "", "");
                    }
                    catch (Exception ex)
                    {
                        // (Si viene de flujo Prospecto) Elimina las empresas en caso de error en la inserción del contacto a F2G 
                        if (Lead_originId != Guid.Empty)
                        {
                            // Elimina Empresa F2G 
                            MetodosFes.EliminaF2GCompy(0, string.Empty, NombreDom, ContactoId, Cliente_Front2Go);
                            // Elimina Empresa CA
                            MetodosFes.EliminaCityAccCompy(string.Empty, ContactoId, Cliente_CityAcc);
                        }

                        // Borramos contacto F2G
                        MetodosFes.EliminaF2GGuest(Resp_Front_ins_guest, Email, NombreDom, Cliente_Front2Go);
                        throw new InvalidPluginExecutionException("Hoteles City ERROR de Integración City Access. No se pudo consumir contrato Insert_guest. Detalle de error: " + ex.Message);
                    }

                    if (Resp_CityAcc_ins_guest < 0)
                    {
                        // (Si viene de flujo Prospecto) Elimina las empresas en caso de error en la inserción del contacto a F2G 
                        if (Lead_originId != Guid.Empty)
                        {
                            // Elimina Empresa F2G 
                            MetodosFes.EliminaF2GCompy(0, string.Empty, NombreDom, ContactoId, Cliente_Front2Go);
                            // Elimina Empresa CA
                            MetodosFes.EliminaCityAccCompy(string.Empty, ContactoId, Cliente_CityAcc);
                        }

                        // Borramos contacto F2G
                        MetodosFes.EliminaF2GGuest(Resp_Front_ins_guest, Email, NombreDom, Cliente_Front2Go);
                        throw new InvalidPluginExecutionException("Hoteles City ERROR de Integración City Access. No se pudo Insertar el Contacto a City Access. Código de error: " + Resp_CityAcc_ins_guest.ToString() + " Detalle: " + MetodosFes.DetalleError(Resp_CityAcc_ins_guest, 6));
                    }

                    #region ENVIAMOS CONTACTO GENERAL A EMPRESA, SIEMPRE Y CUANDO F2G Y CA ES: OK 
                    // Si la inserción fue correcta, entonces asignamos el contacto a la empresa
                    if (Resp_Front_ins_guest > 0 && Resp_CityAcc_ins_guest > 0)
                        AsignaContactoAempresa(Mensaje, Cliente_Front2Go, Cliente_Prop, Cliente_CityAcc, Contacto, EsPrincipal, TipoPersona_co, Serv, Resp_Front_ins_guest, Email, Resp_CityAcc_ins_guest, NombreDom);
                    #endregion
                   
                }             
            }
            #endregion

            #region UPDATE - INTEGRACION F2G - CITY ACCESS
            // Verificamos que el mensaje sea de Actualización
            if (Mensaje.Equals("Update"))
            {
                // Recuperamos el valor del ID de la inserción del Contacto que da  City Access
                Resp_CityAcc_ins_guest = Contacto.Attributes.Contains("new_resp_ca_ins_guest") ? (int)Contacto.Attributes["new_resp_ca_ins_guest"] : 0; 

                #region  Actualizamos Contacto / Huesped a Front2Go 
                Resp_Front_upd_guest = Cliente_Front2Go.UpdatePerson(5, Apellidos_co, Nombres_co, Titulo_co, Tel_co, Email, ClasePer, "Activo", Frqtvl_num, Frqtvl, TipoDir_co, "", "", Pais_co, Direccion, 00000, NombreDom);

                if (int.Parse(Resp_Front_upd_guest).Equals(0))
                    // Actualizamos Contacto / Huesped a CityAcccess
                    Resp_CityAcc_upd_guest = Cliente_CityAcc.Update_guest(TipoPersona_co.ToString(), Apellidos_co, Nombres_co, Titulo_co, Tel_co, Email, ClasePer, "Activo", Frqtvl_num, Frqtvl, TipoDir_co, "", "", Pais_co, Direccion, "0");

                if (int.Parse(Resp_Front_upd_guest) != 0)
                    throw new InvalidPluginExecutionException("Hoteles City ERROR de Integración Front2Go. No se pudo Actualizar el Contacto a Front2Go. Código de error: " + Resp_Front_upd_guest + " Detalle: " + MetodosFes.DetalleError(int.Parse(Resp_Front_upd_guest), 7));

                if (Resp_CityAcc_upd_guest != 0)
                    throw new InvalidPluginExecutionException("Hoteles City ERROR de Integración CityAccess. No se pudo Actualizar el Contacto a City Access. Código de error: " + Resp_CityAcc_upd_guest.ToString() + " Detalle: " + MetodosFes.DetalleError(Resp_CityAcc_upd_guest, 8));
                #endregion

                // Si el valor de la empresa, se actualizó, entonces mandamos llamar de nuevo el setpersontocompany
                if (EntContexto.Attributes.Contains("parentcustomerid"))
                    AsignaContactoAempresa(Mensaje, Cliente_Front2Go, Cliente_Prop, Cliente_CityAcc, Contacto, EsPrincipal, TipoPersona_co, Serv, Resp_Front_ins_guest, Email, Resp_CityAcc_ins_guest, NombreDom);
            }
            #endregion

            #region Actualización de estados en CRM
            try
            {
                Entity ActEdoInte = new Entity("contact");
                ActEdoInte.Attributes["contactid"] = ContactoId;

                if (Mensaje.Equals("Create"))
                {
                    ActEdoInte.Attributes["new_resp_ftg_ins_guest"] = Resp_Front_ins_guest;
                    ActEdoInte.Attributes["new_resp_ca_ins_guest"] = Resp_CityAcc_ins_guest;
                }

                if (Mensaje.Equals("Update"))
                {
                    ActEdoInte.Attributes["new_resp_ftg_upd_guest"] = int.Parse(Resp_Front_upd_guest); 
                    ActEdoInte.Attributes["new_resp_ca_upd_guest"] = Resp_CityAcc_upd_guest; 
                }

                Serv.Update(ActEdoInte);            
            }
            catch (Exception ex)
            {
                if (Mensaje.Equals("Create"))
                {
                    //Elimina Contacto 
                    MetodosFes.EliminaF2GGuest(Resp_Front_ins_guest, Email, NombreDom, Cliente_Front2Go);
                    //Rollback CA
                    MetodosFes.EliminaCityAccGuest(Email, Cliente_CityAcc);
                }
                throw new InvalidPluginExecutionException("Hoteles City ERROR CRM Actualización de estados en Formulario Contactos. " + ex.Message);
            }
            #endregion        
        }

        // Funcion que enrola un contacto a una empresa, se manda llamar en la creación y en la actualización 
        private void AsignaContactoAempresa(string Msj, ws_PerfilesSoapClient Cliente_Front2Go, ws_ConveniosSoapClient Cliente_Prop, CityAccessWSSoapClient Cliente_CityAcc, Entity Cont, bool Principal, int TipoPers, IOrganizationService Serv, int sellogst, string mail, int Id_Contact_ca, string usrdom)
        {
             Guid EmpresaId = Guid.Empty;
             Guid ContactId = Guid.Empty;
             Guid Lead_originId = Guid.Empty;

            //int Resp_CityAcc_SetPersonComp = 100;   
            string Relacion = "GENERAL";
            string Code_com = string.Empty;
            string NomEntidad = string.Empty;

            string TipoCompySetPers = string.Empty;

            cRespuestaAsociacion RespAso_F2G = null;
            Resultado Resp_CityAcc_SetPersonComp = null;
          
            // Recuperamos la empresa que trae el contacto
            if (MetodosFes.ExisteAtributo("parentcustomerid", Cont))
            {
                EmpresaId = ((EntityReference)Cont.Attributes["parentcustomerid"]).Id;
                ContactId = (Guid)Cont.Attributes["contactid"];
                Lead_originId = Cont.Attributes.Contains("originatingleadid") ? ((EntityReference)Cont.Attributes["originatingleadid"]).Id : Guid.Empty;
                //NomEntidad = ((EntityReference)Cont.Attributes["parentcustomerid"]).Name;
            }

            // Si existe, entonces recuperamos su Email y mandamos enrolarlo a la cuenta
            if (EmpresaId != Guid.Empty)
            {
                Entity Emp = Serv.Retrieve("account", EmpresaId, new ColumnSet("accountnumber", "primarycontactid", "new_tipocompy", "new_resp_ca_ins_cmp"));

                int TipoCompyCode = Emp.Attributes.Contains("new_tipocompy") ? ((OptionSetValue)Emp.Attributes["new_tipocompy"]).Value : 0;
                int Id_Cmpy_ca = Emp.Attributes.Contains("new_resp_ca_ins_cmp") ? (int)Emp.Attributes["new_resp_ca_ins_cmp"] : 0;

                #region Tratamiento Para enviarle al SetPersonToCompany si es A o C
                if (TipoCompyCode.Equals(2) || TipoCompyCode.Equals(3))
                {
                    TipoCompySetPers = "A";
                }
                else
                {
                    TipoCompySetPers = "C";
                }
                #endregion


                // Si La empresa ya tiene un contacto principal, entonces el contacto debe ser general
                if (MetodosFes.ExisteAtributo("primarycontactid", Emp))
                    Relacion = "GENERAL";
                else // Si no tiene contacto principal, entonces se le asigna
                {
                    Relacion = "PRINCIPAL";

                    #region Actualizamos en la Empresa el contacto en cuestión, como principal, al no haber contacto principal                   
                    //Actualizamos la cuenta con el contacto en cuestion para que sea principal
                    try
                    {
                        Entity Upd_Empr_Princ = new Entity("account");
                        Upd_Empr_Princ.Attributes["accountid"] = EmpresaId;
                        Upd_Empr_Princ.Attributes["primarycontactid"] = new EntityReference("contact", (Guid)Cont.Attributes["contactid"]);
                        Serv.Update(Upd_Empr_Princ);
                    }
                    catch(Exception ex)
                    {
                        // (Si viene de flujo Prospecto) Elimina las empresas en caso de error en la inserción del contacto a F2G 
                        if (Lead_originId != Guid.Empty)
                        {
                            // Elimina Empresa F2G 
                            MetodosFes.EliminaF2GCompy(0, string.Empty, usrdom, ContactId, Cliente_Front2Go);
                            // Elimina Empresa CA
                            MetodosFes.EliminaCityAccCompy(string.Empty, ContactId, Cliente_CityAcc);
                        }

                        /*Si es en la creación del contacto y hay error, entonces sí elimina el contacto en F2G*/
                        if (Msj.Equals("Create"))
                        {
                            // Elimina Contacto en F2G
                            MetodosFes.EliminaF2GGuest(sellogst, mail, usrdom, Cliente_Front2Go);
                            // Elimina Contacto en CA
                            MetodosFes.EliminaCityAccGuest(mail, Cliente_CityAcc);
                        }

                        throw new InvalidPluginExecutionException("CRM ERROR. Hubo un problema al actualizar el contacto como principal en la Empresa. Detalle: " + ex.Message);
                    }
                    #endregion
                }


                // Recuperamos el código de compañia   
                if (MetodosFes.ExisteAtributo("accountnumber", Emp))
                    Code_com = (string)Emp.Attributes["accountnumber"];

                // Si existe correo y código de compañia (convenio)
                if (mail != string.Empty && Code_com != string.Empty)
                {
                    try
                    {
                        // FRONT2GO -  Mandamos llamar el metodo que asocia el contacto, Siempre y cuando la Empresa haya sido creada correctamente
                        RespAso_F2G = Cliente_Prop.SetPersonToCompany(Code_com, mail, Relacion, TipoCompySetPers);
                    }
                    catch (Exception ex)
                    {
                        // (Si viene de flujo Prospecto) Elimina las empresas en caso de error en la inserción del contacto a F2G 
                        if (Lead_originId != Guid.Empty)
                        {
                            // Elimina Empresa F2G 
                            MetodosFes.EliminaF2GCompy(0, string.Empty, usrdom, ContactId, Cliente_Front2Go);
                            // Elimina Empresa CA
                            MetodosFes.EliminaCityAccCompy(string.Empty, ContactId, Cliente_CityAcc);
                        }

                        /*Si es en la creación del contacto y hay error, entonces sí elimina el contacto en F2G*/
                        if (Msj.Equals("Create"))
                        {
                            // Elimina Contacto en F2G
                            MetodosFes.EliminaF2GGuest(sellogst, mail, usrdom, Cliente_Front2Go);
                            // Elimina Contacto en CA
                            MetodosFes.EliminaCityAccGuest(mail, Cliente_CityAcc);
                        }

                        throw new InvalidPluginExecutionException("Front2Go SetPersonToCompany (Contacto). Error al consumir el método. Detalle: " + ex.Message);
                    }

                    if (!RespAso_F2G.AsociacionCorrecta)
                    {
                        // (Si viene de flujo Prospecto) Elimina las empresas en caso de error en la inserción del contacto a F2G 
                        if (Lead_originId != Guid.Empty)
                        {
                            // Elimina Empresa F2G 
                            MetodosFes.EliminaF2GCompy(0, string.Empty, usrdom, ContactId, Cliente_Front2Go);
                            // Elimina Empresa CA
                            MetodosFes.EliminaCityAccCompy(string.Empty, ContactId, Cliente_CityAcc);
                        }

                        /*Si es en la creación del contacto y hay error, entonces sí elimina el contacto en F2G*/
                        if (Msj.Equals("Create"))
                        {
                            // Elimina Contacto en F2G
                            MetodosFes.EliminaF2GGuest(sellogst, mail, usrdom, Cliente_Front2Go);
                            // Elimina Contacto en CA
                            MetodosFes.EliminaCityAccGuest(mail, Cliente_CityAcc);
                        }

                        throw new InvalidPluginExecutionException("Front2Go SetPersonToCompany (Contacto). La asociación no se realizó correctamente debido a: " + RespAso_F2G.DescError);
                    }

                    //// Si la respuesta del servicio de Front2Go fue correcta, enviamos la relación a City Access
                    if (RespAso_F2G.AsociacionCorrecta && Id_Cmpy_ca > 0 && Id_Contact_ca > 0)
                        Resp_CityAcc_SetPersonComp = Cliente_CityAcc.SetPersonToCompany(Relacion, Id_Cmpy_ca, Id_Contact_ca);

                    if (int.Parse(Resp_CityAcc_SetPersonComp.Codigo) < 0)
                    {
                        // (Si viene de flujo Prospecto) Elimina las empresas en caso de error en la inserción del contacto a F2G 
                        if (Lead_originId != Guid.Empty)
                        {
                            // Elimina Empresa F2G 
                            MetodosFes.EliminaF2GCompy(0, string.Empty, usrdom, ContactId, Cliente_Front2Go);
                            // Elimina Empresa CA
                            MetodosFes.EliminaCityAccCompy(string.Empty, ContactId, Cliente_CityAcc);
                        }

                        /*Si es en la creación del contacto y hay error, entonces sí elimina el contacto en F2G*/
                        if (Msj.Equals("Create"))
                        {
                            // Elimina Contacto en F2G
                            MetodosFes.EliminaF2GGuest(sellogst, mail, usrdom, Cliente_Front2Go);
                            // Elimina Contacto en CA
                            MetodosFes.EliminaCityAccGuest(mail, Cliente_CityAcc);
                        }

                        throw new InvalidPluginExecutionException("City Access SetPersonToCompany (Contacto). La asociación no se realizó correctamente. Descripción del Error: " + Resp_CityAcc_SetPersonComp.Descripcion.ToString());
                    }
                }
                else
                {
                    // (Si viene de flujo Prospecto) Elimina las empresas en caso de error en la inserción del contacto a F2G 
                    if (Lead_originId != Guid.Empty)
                    {
                        // Elimina Empresa F2G 
                        MetodosFes.EliminaF2GCompy(0, string.Empty, usrdom, ContactId, Cliente_Front2Go);
                        // Elimina Empresa CA
                        MetodosFes.EliminaCityAccCompy(string.Empty, ContactId, Cliente_CityAcc);
                    }

                    /*Si es en la creación del contacto y hay error, entonces sí elimina el contacto en F2G*/
                    if (Msj.Equals("Create"))
                    {
                        MetodosFes.EliminaF2GGuest(sellogst, mail, usrdom, Cliente_Front2Go);
                        MetodosFes.EliminaCityAccGuest(mail, Cliente_CityAcc);
                    }

                    throw new InvalidPluginExecutionException("Front2Go SetPersonToCompany (Contacto). El contacto no cuenta con dirección de correo electrónico, no se puede asociar a la Empresa.");
                }
            }
            else
            {
                /*Si es en la creación del contacto y hay error, entonces sí elimina el contacto en F2G*/
                //if (Msj.Equals("Create"))
                    //MetodosFes.EliminaF2GGuest(sellogst, mail, usrdom);

                //throw new InvalidPluginExecutionException("Front2Go SetPersonToCompany. El contacto no cuenta tiene una empresa relacionada, no se puede asociar.");
            }
        }        
    }

    /// <summary>
    /// Autor: Julio Esquivel 
    /// Fecha Junio 2014
    /// Descripción: Integración con F2G y City Access.
    /// Entidad: Empresa (account)
    /// Métodos: Assign 
    /// Contratos: SetOwnerToCompany
    /// </summary>
    /// 
    public class IntegraPropietario : IPlugin
    {
        public void Execute(IServiceProvider ProveedorServicio)
        {            
            // Limpiamos objetos de entidad y WS
            EntityReference Entidad = null;
            IOrganizationService Servicio = null;

            try
            {
                //Obtenemos el Contexto de ejecución del Plugin
                IPluginExecutionContext Contexto = (IPluginExecutionContext)ProveedorServicio.GetService(typeof(IPluginExecutionContext));

                // Validamos que exista un objeto de tipo Entity
                Entidad = ValidaContexto(Contexto, ProveedorServicio);

                // Consumimos el Servicio de Organización      
                Servicio = OrganizationServiceCrm.ObtenerServicioCallingUser(Contexto, ProveedorServicio);

                // Pasamos Objeto de Servicio a los métodos FesXrm
                MetodosFes InicializaServicio = new MetodosFes(Servicio);

                // Validamos que la entidad realmente sea Empresa
                if (Contexto.PrimaryEntityName.Equals("account"))
                {
                    Guid OldOwner = Guid.Empty;
                    string NombreDomNew = string.Empty;
                    string NombreDomOld = string.Empty;
                    string Convenio = string.Empty;

                    // Configuramos Binding de Servicios          
                    BasicHttpBinding AsignaProp_bin = new BasicHttpBinding();

                    AsignaProp_bin.Name = "ws_ConveniosSoap";

                    EndpointAddress EndPointAsignProp = new EndpointAddress("http://200.79.228.19/whsEngine/ws_Convenios.asmx");

                    // Instanciamos el objeto de los servicios                                                   
                    ws_ConveniosSoapClient Cliente_Prop = new ws_ConveniosSoapClient(AsignaProp_bin, EndPointAsignProp);

                    // Guid del Nuevo Propietario al que se va asignar, proviene del contexto
                    Guid NewOwner = ((EntityReference)Contexto.InputParameters["Assignee"]).Id;
                    Entity Emp = Servicio.Retrieve("account", Contexto.PrimaryEntityId, new ColumnSet("ownerid", "new_rfc", "accountnumber"));

                    // Recuperamos lo que hay en la Empresa, dependiendo del Contexto
                    if (MetodosFes.ExisteAtributo("ownerid", Emp))
                        OldOwner = ((EntityReference)Emp.Attributes["ownerid"]).Id;

                    // Recuperamos el RFC de la empresa *
                    if (MetodosFes.ExisteAtributo("accountnumber", Emp))
                        Convenio = (string)Emp.Attributes["accountnumber"];

                    Entity PropietarioNuevo = Servicio.Retrieve("systemuser", NewOwner, new ColumnSet("domainname", "new_nombref2g"));
                    Entity PropietarioViejo = Servicio.Retrieve("systemuser", OldOwner, new ColumnSet("domainname", "new_nombref2g"));

                    //if (MetodosFes.ExisteAtributo("domainname", PropietarioNuevo))
                    if (MetodosFes.ExisteAtributo("new_nombref2g", PropietarioNuevo))
                    {
                        NombreDomNew = (string)PropietarioNuevo.Attributes["new_nombref2g"];
                        //NombreDomNew = MetodosFes.DevuelveNombre(NombreDomNew);

                    }

                    //if (MetodosFes.ExisteAtributo("domainname", PropietarioViejo))
                    if (MetodosFes.ExisteAtributo("new_nombref2g", PropietarioViejo))
                    {
                        NombreDomOld = (string)PropietarioViejo.Attributes["new_nombref2g"];
                        //NombreDomOld = MetodosFes.DevuelveNombre(NombreDomOld);
                    }

                    // Si trae información, se envían los nombres por integración
                    if (NombreDomNew != string.Empty && NombreDomOld != string.Empty && Convenio != string.Empty)
                    {
                        cResponseOwner RespOwn = Cliente_Prop.SetOwnerByCompany(NombreDomOld, NombreDomNew, Convenio);

                         if (RespOwn.ErrorCode != 0)
                             throw new InvalidPluginExecutionException("Error Integración Front2Go SetOwnerByCompany - Asignación Propietario: " + RespOwn.ErrorMessage);
                    }
                    
                    //throw new InvalidPluginExecutionException("Prop Nuevo / Prop Viejo: " + NombreDomNew + " / " + NombreDomOld);
                    
                    
                }
            }
            catch (FaultException<OrganizationServiceFault> ex)
            {
                throw new InvalidPluginExecutionException("Hoteles City ERROR de Integración Asignando Propietario. " + ex.Message);
            }
        }

        #region # Método de validación del Contexto que recibe el Plugin
        private EntityReference ValidaContexto(IPluginExecutionContext Context, IServiceProvider Prov_Servicio)
        {
            EntityReference Ent = null;

            if (Context.InputParameters.Contains("Target") && Context.InputParameters["Target"] is EntityReference)
                Ent = (EntityReference)Context.InputParameters["Target"];

            return Ent;
        }
        #endregion
    }

}
